﻿//  --------------------------------------------------------------------------------------
//  MiscellaneousHelpers.js
//  --------------------------------------------------------------------------------------

var g_AtomNamespaceURI = "http://www/w3/org/2005/Atom";

function AttachEvent(i_Element, i_EventType, i_EventHandler)
    {
    if (i_Element.addEventListener != null)
        {
        i_Element.addEventListener
            (
            i_EventType, 
            i_EventHandler, 
            false
            );
        }
    else if (i_Element.attachEvent != null)
        {
        i_Element.attachEvent
            (
            'on' + i_EventType, 
            i_EventHandler
            );
        }
    else
        {
        alert('Unable to attach events!');
        }
    }
    
function DetachEvent(i_Element, i_EventType, i_EventHandler)
    {
    if (i_Element.removeEventListener != null)
        {
        i_Element.removeEventListener
            (
            i_EventType, 
            i_EventHandler, 
            false
            );
        }
    else if (i_Element.detachEvent != null)
        {
        i_Element.detachEvent
            (
            'on' + i_EventType, 
            i_EventHandler
            );
        }
    else
        {
        alert('Unable to detach events!');
        }
    }

function ConvertDateToRFC3339DateTime(i_Date)
    {
    var CurrentDateTime = null;
    if (i_Date != null)
        CurrentDateTime = new Date(i_Date);
    else
        CurrentDateTime = new Date();

    var Year = CurrentDateTime.getYear();
    if (Year < 70)
        Year += 2000;
    else if (Year < 1900)
        Year += 1900;

    var Month = CurrentDateTime.getMonth() + 1;
    if (Month <= 9)
        Month = "0" + Month;

    var Day = CurrentDateTime.getDate();
    if (Day <= 9)
        Day = "0" + Day;

    var HourUTC = CurrentDateTime.getUTCHours();
    if (HourUTC <= 9)
        HourUTC = "0" + HourUTC;

    var MinuteUTC = CurrentDateTime.getUTCMinutes();
    if (MinuteUTC <= 9)
        MinuteUTC = "0" + MinuteUTC;
        
    var Second = CurrentDateTime.getSeconds();
    if (Second <= 9)
        Second = "0" + Second;

    var RFC3339DateTime = Year + "-" + Month + "-" + Day + "T" + HourUTC + ":" + MinuteUTC + ":" + Second + "Z";
    return RFC3339DateTime;       
    }

function ConvertRFC3339DateTimeToDate(i_RFC3339DateTime)
    {
    i_RFC3339DateTime = i_RFC3339DateTime.toLowerCase();
    var DateTimeParts = i_RFC3339DateTime.split("t");
    
    var DateParts = DateTimeParts[0].split("-");
    var Year = new Number(DateParts[0]);
    var Month = new Number(DateParts[1]) - 1;
    var Day = new Number(DateParts[2]);
    
    var TimeParts = DateTimeParts[1].split(":");
    var Hours = new Number(TimeParts[0]);
    var Minutes = new Number(TimeParts[1]);
    var Seconds = TimeParts[2];
    Seconds = new Number(Seconds.substr(0, Seconds.indexOf("z")));
    
    var MillisecondsSince1970 = Date.UTC
        (
        Year,
        Month,
        Day,
        Hours,
        Minutes,
        Seconds
        );
    
    return new Date(MillisecondsSince1970);
    }

function StopEventBubbling(i_Event)
    {
    if (i_Event == null)
        throw "i_Event can't be null!";
        
    if (i_Event.stopPropagation)
        {
        //  W3C method
        i_Event.stopPropagation();
        }
    else
        {
        //  IE method
        i_Event.cancelBubble = true;
        }
    }

function GetBooleanAttributeValue(i_XMLDOMElement, i_AttributeName)
    {
    var AttributeValue = i_XMLDOMElement.getAttribute(i_AttributeName);
    return parseBool(AttributeValue);
    }

function parseBool(i_Value)
    {
    if (isNaN(parseInt(i_Value)))
        {
        i_Value = i_Value + "";
        if (i_Value.toLowerCase() == "true")
            return true;
            
        return false;
        }
    
    i_Value = i_Value + 0;
        
    return Boolean(i_Value);
    }
    
function GetSourceElementFromEvent(i_Event)
    {
    if (i_Event == null)
        i_Event = window.event;

    var SourceElement = null;
    if (i_Event.target != null)
        SourceElement = i_Event.target;
    else if (i_Event.srcElement != null)
        SourceElement = i_Event.srcElement;        
    
    return SourceElement;
    }
    
function XMLEncode(i_String)
    {
    i_String = i_String.replace("&", "&amp;");
    i_String = i_String.replace(">", "&gt;");
    i_String = i_String.replace("<", "&lt;");
    i_String = i_String.replace("\"", "&quot;");
    i_String = i_String.replace("'", "&#39;");
    
    return i_String;
    }
    
function XMLDecode(i_String)
    {
    i_String = i_String.replace("&amp;", "&");
    i_String = i_String.replace("&gt;", ">");
    i_String = i_String.replace("&lt;", "<");
    i_String = i_String.replace("&quot;", "\"");
    i_String = i_String.replace("&#39;", "'");
    
    return i_String;
    }

function CreateXMLDOMDocument()
    {
    var XMLDOMDocument = null;
    
    if (IsFirefox())
        {
        XMLDOMDocument = document.implementation.createDocument
            (
            "",
            "",
            null
            );
        }
    else
        {
        XMLDOMDocument = new ActiveXObject("Microsoft.XMLDOM");
        }
        
    return XMLDOMDocument;
    }
    
function LoadXML(i_SourceLocation, i_ThrowOnFailure)
    {
    var XMLDOMDocument = CreateXMLDOMDocument();
    
    XMLDOMDocument.async = false;
    if (!XMLDOMDocument.load(i_SourceLocation))
        XMLDOMDocument = null;

    if ((XMLDOMDocument == null) && i_ThrowOnFailure)
        throw "unable to load xml!";

    return XMLDOMDocument;
    }
        
function ParseXML(i_XML, i_ThrowOnFailure)
    {
    var XMLDOMDocument = null;
    
    if (IsFirefox())
        {
        var Parser = new DOMParser();
        XMLDOMDocument = Parser.parseFromString
            (
            i_XML,
            "text/xml"
            );
            
        if (XMLDOMDocument.documentElement.nodeName == 'parsererror')
            XMLDOMDocument = null;
        }
    else
        {
        XMLDOMDocument = new ActiveXObject("Microsoft.XMLDOM");
        XMLDOMDocument.async = false;
        if (!XMLDOMDocument.loadXML(i_XML))
            XMLDOMDocument = null;
        }

    if ((XMLDOMDocument == null) && i_ThrowOnFailure)
        throw "unable to load xml!";

    return XMLDOMDocument;
    }

function SelectSingleNode(i_XMLDOMElement, i_XPathExpression, i_Namespaces, i_ThrowOnFailure)
    {
    var Node = null;
    
    if (IsFirefox())
        {
        var NamespaceResolver = null;
        var Dictionary = null;

        if (i_Namespaces != null)
            {
            Dictionary = new Object();

            for (var Index = 0; Index < i_Namespaces.length; ++Index)
                {
                var Namespace = i_Namespaces[Index];
                var NamespaceParts = Namespace.split("=");
                var NamespacePrefix = NamespaceParts[0].split(":")[1];
                var NamespaceURI = NamespaceParts[1].replace(/'/g, "");
                
                Dictionary[NamespacePrefix] = NamespaceURI;
                }
            
            NamespaceResolver = function nsResolver(i_Prefix)
                {
                return Dictionary[i_Prefix] || null;
                }
            }

        var Result = i_XMLDOMElement.ownerDocument.evaluate
            (
            i_XPathExpression,
            i_XMLDOMElement,
            NamespaceResolver,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
            );
        
        if (Result != null)
            Node = Result.singleNodeValue;
        }
    else
        {
        if (i_Namespaces != null)
            {
            var SelectionNamespaces = i_XMLDOMElement.ownerDocument.getProperty("SelectionNamespaces");
            if (SelectionNamespaces == null)
                SelectionNamespaces = "";
            
            for (var Index = 0; Index < i_Namespaces.length; ++Index)
                {
                var Namespace = i_Namespaces[Index];
                if (SelectionNamespaces.indexOf(Namespace) == -1)
                    SelectionNamespaces += Namespace + " ";
                }
            
            i_XMLDOMElement.ownerDocument.setProperty
                (
                "SelectionNamespaces", 
                SelectionNamespaces
                );
            }

        Node = i_XMLDOMElement.selectSingleNode(i_XPathExpression);
        }
    
    if ((Node == null) && i_ThrowOnFailure)
        throw "SelectSingleNode failed!";
        
    return Node;
    }

function SelectNodes(i_XMLDOMElement, i_XPathExpression, i_Namespaces, i_ThrowIfEmpty)
    {
    var Nodes = new Array();
    
    if (IsFirefox())
        {
        var NamespaceResolver = null;
        var Dictionary = null;

        if (i_Namespaces != null)
            {
            Dictionary = new Object();

            for (var Index = 0; Index < i_Namespaces.length; ++Index)
                {
                var Namespace = i_Namespaces[Index];
                var NamespaceParts = Namespace.split("=");
                var NamespacePrefix = NamespaceParts[0].split(":")[1];
                var NamespaceURI = NamespaceParts[1].replace(/'/g, "");
                
                Dictionary[NamespacePrefix] = NamespaceURI;
                }
            
            NamespaceResolver = function nsResolver(i_Prefix)
                {
                return Dictionary[i_Prefix] || null;
                }
            }

        var Result = i_XMLDOMElement.ownerDocument.evaluate
            (
            i_XPathExpression,
            i_XMLDOMElement,
            NamespaceResolver,
            XPathResult.ORDERED_NODE_ITERATOR_TYPE,
            null
            );
        
        if (Result != null)
            {
            var Node = Result.iterateNext();
            while (Node)
                {
                Nodes.push(Node);
                Node = Result.iterateNext();
                }
            }
        }
    else
        {
        if (i_Namespaces != null)
            {
            var SelectionNamespaces = i_XMLDOMElement.ownerDocument.getProperty("SelectionNamespaces");
            if (SelectionNamespaces == null)
                SelectionNamespaces = "";
            
            for (var Index = 0; Index < i_Namespaces.length; ++Index)
                {
                var Namespace = i_Namespaces[Index];
                if (SelectionNamespaces.indexOf(Namespace) == -1)
                    SelectionNamespaces += Namespace + " ";
                }
            
            i_XMLDOMElement.ownerDocument.setProperty
                (
                "SelectionNamespaces", 
                SelectionNamespaces
                );
            }

        Nodes = i_XMLDOMElement.selectNodes(i_XPathExpression);
        }
    
    if ((Nodes.length == 0) && i_ThrowIfEmpty)
        throw "SelectNodes failed!";
        
    return Nodes;
    }

function ImportNode(i_XMLDOMDocument, i_XMLDOMNode, i_IncludeChildren)
    {
    var ImportedNode = null
    if (IsFirefox())
        {
        ImportedNode = i_XMLDOMDocument.importNode
            (
            i_XMLDOMNode,
            i_IncludeChildren
            );
        }
    else
        {        
        switch (i_XMLDOMNode.nodeType)
            {
            case 1:  // ELEMENT_NODE
                {
                ImportedNode = i_XMLDOMDocument.createElement(i_XMLDOMNode.nodeName);

                if (i_XMLDOMNode.attributes && (i_XMLDOMNode.attributes.length > 0))
                    {
                    for (var Index = 0; Index < i_XMLDOMNode.attributes.length; ++Index)
                        {
                        ImportedNode.setAttribute
                            (
                            i_XMLDOMNode.attributes[Index].nodeName, 
                            i_XMLDOMNode.getAttribute(i_XMLDOMNode.attributes[Index].nodeName)
                            );
                        }
                    }
                        
                if (i_IncludeChildren && (i_XMLDOMNode.childNodes != null) && (i_XMLDOMNode.childNodes.length > 0))
                    {
                    for (var Index = 0; Index < i_XMLDOMNode.childNodes.length; ++Index)
                        {
                        var ChildImportedNode = ImportNode
                                (
                                i_XMLDOMDocument,
                                i_XMLDOMNode.childNodes[Index], 
                                i_IncludeChildren
                                )

                        ImportedNode.appendChild(ChildImportedNode);
                        }
                    }
                    
                break;
                }
                
            case 3:  // TEXT_NODE 
            case 4:  // CDATA_SECTION_NODE
            case 8:  // COMMENT_NODE
                {
                ImportedNode = i_XMLDOMDocument.createTextNode(i_XMLDOMNode.nodeValue);
                break;
                }
                
            default:
                {
                throw "Unhandled node type!";
                }
            }
        }
                
        return ImportedNode;
    }

function GetLocalName(i_DOMNode)
    {
    if (IsFirefox())
        return i_DOMNode.localName;
    
    return i_DOMNode.baseName;
    }
        
function GetXML(i_DOMNode)
    {
    if (IsFirefox())
        {
        var Serializer = new XMLSerializer();
        return Serializer.serializeToString(i_DOMNode);
        }

    return i_DOMNode.xml;
    }

function GetTextForXMLDOMNode(i_XMLDOMNode)
    {
    if (IsFirefox())
        return i_XMLDOMNode.textContent;

    return i_XMLDOMNode.text;
    }

function SetTextForXMLDOMNode(i_XMLDOMNode, i_Value)
    {
    if (IsFirefox())
        i_XMLDOMNode.textContent = i_Value;
    else
        i_XMLDOMNode.text = i_Value;
    }

function GetTextForHTMLDOMNode(i_HTMLDOMNode, i_Value)
    {
    if (IsFirefox())
        return i_HTMLDOMNode.innerHTML;
        
    return i_HTMLDOMNode.innerText;
    }

function SetTextForHTMLDOMNode(i_HTMLDOMNode, i_Value)
    {
    if (IsFirefox())
        i_HTMLDOMNode.textContent = i_Value;
    else
        i_HTMLDOMNode.innerText = i_Value;
    }
        
function CreateXMLDOMElement(i_DOMDocument, i_ElementName, i_NamespaceURI)
    {
    var XMLDOMElement = null;
    
    if (i_NamespaceURI == null)
        i_NamespaceURI = "";
        
    if (IsFirefox())
        {
        XMLDOMElement = i_DOMDocument.createElementNS
            (
            i_NamespaceURI,
            i_ElementName
            );
        }
    else
        {
        XMLDOMElement = i_DOMDocument.createNode
            (
            1, // NODE_ELEMENT
            i_ElementName,
            i_NamespaceURI
            );
        }
        
    return XMLDOMElement;
    }        

function GetXMLDOMElement(i_ParentXMLDOMElement, i_ElementName, i_NamespaceDeclarations, i_CreateIfNotFound, i_NamespaceURI)
    {
    var XMLDOMElement = SelectSingleNode
        (
        i_ParentXMLDOMElement,
        i_ElementName,
        i_NamespaceDeclarations,
        false
        );
        
    if ((XMLDOMElement == null) && i_CreateIfNotFound)
        {
        XMLDOMElement = CreateXMLDOMElement
            (
            i_ParentXMLDOMElement.ownerDocument,
            i_ElementName,
            i_NamespaceURI
            );
        }

    return XMLDOMElement;
    }
    
function IsFirefox()
    {
    return (navigator.userAgent.toLowerCase().indexOf("firefox") != -1);
    }
    
function IsNullOrEmpty(i_String)
    {
    return ((i_String == null) || (i_String == ""));
    }
    
function IsRSSFeed(i_XMLDOMDocument)
    {
    return (i_XMLDOMDocument.documentElement.baseName == "rss");
    }

function IsAtomFeed(i_XMLDOMDocument)
    {
    return (i_XMLDOMDocument.documentElement.baseName == "atom");
    }
    
function GetItemContainerXMLElement(i_XMLDOMDocument)
    {
    var NamespaceDeclarations = new Array();

    //  Remove all items
    if (IsRSSFeed(i_XMLDOMDocument))
        ItemContainerXPathPart = "//rss/channel";
    else if (IsAtomFeed(i_XMLDOMDocument))
        {
        NamespaceDeclarations[0] = "xmlns:atom='" + g_AtomNamespaceURI + "'";
        ItemContainerXPathPart = "//feed";
        }
    else
        throw "Unknown document type!";

    var ItemContainerXmlElement = SelectSingleNode
        (
        i_XMLDOMDocument.documentElement,
        ItemContainerXPathPart,
        NamespaceDeclarations,
        true
        );
        
    return ItemContainerXmlElement;
    }
    
function CreateEmptyFeedXMLDOMDocument(i_XMLDOMDocument)
    {
    var ItemContainerXmlElement = GetItemContainerXMLElement(i_XMLDOMDocument);

    var ParentNode = null;
    if (IsRSSFeed(i_XMLDOMDocument))
        ParentNode = ItemContainerXmlElement.parentNode;
    else
        ParentNode = i_XMLDOMDocument;

    var ClonedItemContainerXmlElement = ItemContainerXmlElement.cloneNode(false);
    ParentNode.removeChild(ItemContainerXmlElement);
    ParentNode.appendChild(ClonedItemContainerXmlElement);
    
    return i_XMLDOMDocument;
    }
    
   
function CreateXMLHTTPObject(i_Verb, i_URL, i_Asynchronous)
    {
    var XMLHTTPObject = null;
    
    if (IsFirefox())
        XMLHTTPObject = new XMLHttpRequest();
    else
        XMLHTTPObject = new ActiveXObject("Microsoft.XMLHTTP");

    XMLHTTPObject.open
        (
        i_Verb,
        i_URL,
        i_Asynchronous
        );

    return XMLHTTPObject;
    }

function PopulateNamespacesForXMLElement(i_Namespaces, i_XMLDOMElement)
    {
    for (var Index = 0; Index < i_XMLDOMElement.childNodes.length; ++Index)
        {
        var ChildNode = i_XMLDOMElement.childNodes[Index];
        if (ChildNode.nodeType != 1)
            continue;

        for (var Index2 = 0; Index2 < ChildNode.attributes.length; ++Index2)
            {
            var Attribute = ChildNode.attributes[Index2];
            if (Attribute.name.indexOf("xmlns") == -1)
                continue;
                
            var NamespacePrefix = "";
            var NamespaceURI = "";
            
            if (Attribute.name.indexOf("xmlns:") != -1)
                NamespacePrefix = Attribute.name.substring(Attribute.name.indexOf(":") + 1);

            NamespaceValue = Attribute.value;
            
            if (!IsNullOrEmpty(NamespaceValue))
                {
                if (i_Namespaces[NamespacePrefix] == null)
                    i_Namespaces[NamespacePrefix] = NamespaceValue;
                else if (i_Namespaces[NamespacePrefix] != NamespaceValue)
                    throw "Different values for same namespace prefix of '" + NamespacePrefix + "'";
                }
            }                    
            
        PopulateNamespacesForXMLElement(i_Namespaces, ChildNode);
        }
    }

function GetNamespacesForXMLDOMDocument(i_XMLDOMDocument)
    {
    var Namespaces = new Object();
    
    PopulateNamespacesForXMLElement(Namespaces, i_XMLDOMDocument.documentElement);
    
    return Namespaces;
    }
    
function GetMappedXMLNamespacePrefix(i_Namespaces, i_PreferredNamespacePrefix, i_NamespaceURI)
    {
    var MappedNamespacePrefix = i_PreferredNamespacePrefix;

    for (var key in i_Namespaces)
    {
        var NamespaceURI = i_Namespaces[key];
        
        if (NamespaceURI != i_NamespaceURI)
            continue;

        if (key == i_PreferredNamespacePrefix)
            break;

        //  Check for default namespace
        if (IsNullOrEmpty(key))
        {
            //  See if prefix used
            if (i_Namespaces[i_PreferredNamespacePrefix] != null)
            {
                //  See if prefix is mapped to namespace uri
                if (i_Namespaces[i_PreferredNamespacePrefix] != i_NamespaceURI)
                {
                    //  Create a new prefix
                    MappedNamespacePrefix = i_PreferredNamespacePrefix + new Date().getTime() + Math.floor(Math.random()*1001);
                }
            }

            break;
        }
    }

    //  Add namespace with mapped prefix
    if (i_Namespaces[MappedNamespacePrefix] == null)
        i_Namespaces[MappedNamespacePrefix] = i_NamespaceURI;

    return MappedNamespacePrefix;
    }
    
function CreateXMLDOMElementHierarchy(i_XMLDOMDocument, i_ParentXMLDOMElement, i_ElementNames, i_NamespaceURIs, i_NamespacePrefixes, i_NamespaceDeclarations, i_AlwaysCreateLastElement)
    {
    if (i_ElementNames.length !=  i_NamespaceURIs.length)
        throw "ElementNames length not same as NamespaceURIs length!";
        
    var XMLDOMElement = null;
    var ParentXMLDOMElement = i_ParentXMLDOMElement;
    
    for (var Index = 0; Index < i_ElementNames.length; ++Index)
        {
        var ElementName = i_ElementNames[Index];
        var NamespaceURI = i_NamespaceURIs[Index];
        var NamespacePrefix = i_NamespacePrefixes[Index];

        var ForceElementCreation = (i_AlwaysCreateLastElement && (Index == i_ElementNames.Length - 1));

        if (!IsNullOrEmpty(NamespacePrefix))
            ElementName = NamespacePrefix + ":" + ElementName;

        if (!ForceElementCreation)
            {
            //  See if node already exists
            XMLDOMElement = SelectSingleNode
                (
                i_ParentXMLDOMElement, 
                ElementName, 
                i_NamespaceDeclarations
                );
                
            ForceElementCreation = (XMLDOMElement == null);
            }

        //  Determine if we should create new node
        if (ForceElementCreation)
            {
            //  Create and append new node
            XMLDOMElement = CreateXMLDOMElement
                (
                i_XMLDOMDocument, 
                ElementName, 
                NamespaceURI
                );
                
            ParentXMLDOMElement.appendChild(XMLDOMElement);
            }

        ParentXMLDOMElement = XMLDOMElement;
        }

        return XMLDOMElement;
    }
